package Thread2;

/**
 * 线程通信的例子：使用两个线程打印1-100，交替打印
 * 涉及到的3个方法
 * wait():执行此方法后，当前线程进入阻塞，并释放同步监视器
 * notify():一旦执行，就会唤醒被wait的一个线程，如果有多个线程被wait
 *          唤醒优先级高的
 * notifyAll():一旦被执行，就会唤醒所有被wait的线程
 *
 * 说明：
 * 1.这3个方法都是在同步代码块或同步方法中使用
 * 2.这3个方法的调用者必须是同步代码块，同步方法中同步监视器中的对象
 *
 * sleep() 和 wait() 的异同
 * 相同点：一旦执行，都可以使得当前线程进入阻塞状态
 * 不同点：1）两个方法的位置不同，Thread类中声明sleep().object类中声明wait（）
 *         2)调用的要求不同，sleep()可以在任何需要的场景下调用，wait()必使用在同步代码块或同步方法中
 *         3）关于是否释放同步监视器：如果两个方法都在使用在同步代码块或同步方法中sleep()不会释放锁，wait（）会释放锁
 */
public class Demo3 {
    public static void main(String[] args) {
        Number n1 = new Number();
        Thread t1 = new Thread(n1);
        Thread t2 = new Thread(n1);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}
class Number implements Runnable{
    private  int num = 1;
    private int total = 0;
    @Override
    public void run() {
        while(true){
            synchronized (this) {
                //唤醒
                notify();
                if(num<=100){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+num);
                    total+=num;
                    num++;

                    try {
                        //调用wait()方法进入阻塞状态
                        //释放锁，线程1进来
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("总和为"+total);
                }else {
                    break;
                }
            }
        }
    }
}